La idea seria hacer una busqueda de un termino en twitter , bajarse los mensajes asociados , pasarlos por un clasificador bayesiano y representar los resultados en Minecraft.
A su vez modificando la geografia que lo anterior genera en Minecraft cambiar los parametros del clasificador Bayesiano para que los siguientes mensajes que lleguen sean clasificados según los nuevos parametros del clasificador.
In [ ]:
In [ ]:
import json
from pprint import pprint
with open('periodicos.json', 'r') as f:
tweets = json.load(f)
#pprint(tweets)
tweets["el_pais"]
In [ ]:
import re
emoticons_str = r"""
(?:
[:=;] # Eyes
[oO\-]? # Nose (optional)
[D\)\]\(\]/\\OpP] # Mouth
)"""
regex_str = [
emoticons_str,
r'<[^>]+>', # HTML tags
r'(?:@[\w_]+)', # @-mentions
r"(?:\#+[\w_]+[\w\'_\-]*[\w_]+)", # hash-tags
r'http[s]?://(?:[a-z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-f][0-9a-f]))+', # URLs
r'(?:(?:\d+,?)+(?:\.?\d+)?)', # numbers
r"(?:[a-z][a-z'\-_]+[a-z])", # words with - and '
r'(?:[\w_]+)', # other words
r'(?:\S)' # anything else
]
tokens_re = re.compile(r'('+'|'.join(regex_str)+')', re.VERBOSE | re.IGNORECASE | re.UNICODE)
emoticon_re = re.compile(r'^'+emoticons_str+'$', re.VERBOSE | re.IGNORECASE | re.UNICODE)
def strip_non_ascii(string):
''' Returns the string without non ASCII characters'''
stripped = (c for c in string if 0 < ord(c) < 127)
return ''.join(stripped)
def strip_less_than_1_chars(string):
''' Returns the string without non ASCII characters'''
stripped = (c for c in string if len(c)>3)
return ''.join(stripped)
def tokenize(s):
return tokens_re.findall(s)
def preprocess(s):
try:
ascii_string = strip_non_ascii(s)
tokens = tokenize(ascii_string)
tokens = [token.lower() for token in tokens if len(token) > 3 and not token.startswith('http')]
return tokens
except TypeError:
return None
tweet = "RT @marcobonzanini: just an example! :D http://example.com #NLP"
print(preprocess(tweets["el_pais"][0][1]))
# ['RT', '@marcobonzanini', ':', 'just', 'an', 'example', '!', ':D', 'http://example.com', '#NLP']
In [ ]:
'http://example.com'.startswith('http')
In [ ]:
tweets_elpais_procesados = [(preprocess(tweet[1]),'positive') for tweet in tweets["el_pais"]]
print(tweets_elpais_procesados)
In [ ]:
#Cambiando un tweet de sentimiento
tweetConNuevoSentimiento = ([u'@elpais_america', u'tras', u'ciudadana', u'corredor', u'chapultepec', u'gobierno', \
u'presentar', u'otros', u'proyectos', u'para', u'transformarlo'], 'negative')
for index,tweet in enumerate(tweets_elpais_procesados):
if tweets_elpais_procesados[index][0] == tweetConNuevoSentimiento[0]:
del tweets_elpais_procesados[index]
tweets_elpais_procesados.append(tweetConNuevoSentimiento)
print(tweets_elpais_procesados)
In [ ]:
import json
from collections import Counter
import nltk
from nltk.corpus import stopwords
import string
tweets_elpais_procesados = [preprocess(tweet) for (fecha,tweet) in tweets["el_pais"]]
punctuation = list(string.punctuation)
stop = stopwords.words('spanish') + punctuation + ['rt', 'via']
count_all = Counter()
terms_all = []
for tweet in tweets_elpais_procesados:
terms_all = [term for term in tweet if term not in stop]
# Update the counter
count_all.update(terms_all)
# Print the first 5 most frequent words
print(count_all.most_common(5))
print(count_all)
Si el codigo anterior da error quizás se tengan que descargar los recursos del nltk con las sentencias:
import nltk
nltk.download()
In [ ]:
# Count terms only once, equivalent to Document Frequency
terms_single = set(terms_all)
# Count hashtags only
terms_hash = [term for term in preprocess(tweet['text'])
if term.startswith('#')]
# Count terms only (no hashtags, no mentions)
terms_only = [term for term in preprocess(tweet['text'])
if term not in stop and
not term.startswith(('#', '@'))]
# mind the ((double brackets))
# startswith() takes a tuple (not a list) if
# we pass a list of inputs
print terms_hash
print ""
print terms_only
In [ ]:
pos_tweets = [('I love this car', 'positive'),
('This view is amazing', 'positive'),
('I feel great this morning', 'positive'),
('I am so excited about the concert', 'positive'),
('He is my best friend', 'positive')]
neg_tweets = [('I do not like this car', 'negative'),
('This view is horrible', 'negative'),
('I feel tired this morning', 'negative'),
('I am not looking forward to the concert', 'negative'),
('He is my enemy', 'negative')]
test_tweets = [
(['feel', 'happy', 'this', 'morning'], 'positive'),
(['larry', 'friend'], 'positive'),
(['not', 'like', 'that', 'man'], 'negative'),
(['house', 'not', 'great'], 'negative'),
(['your', 'song', 'annoying'], 'negative')]
In [ ]:
tweets = []
for (words, sentiment) in pos_tweets + neg_tweets:
words_filtered = [e.lower() for e in words.split() if len(e) >= 3]
tweets.append((words_filtered, sentiment))
print (tweets)
In [ ]:
# The list of word features need to be extracted from the tweets.
# It is a list with every distinct words ordered by frequency of appearance.
# We use the following function to get the list plus the two helper functions.
def get_words_in_tweets(tweets):
all_words = []
for (words, sentiment) in tweets:
all_words.extend(words)
return all_words
def get_word_features(wordlist):
wordlist = nltk.FreqDist(wordlist)
word_features = wordlist.keys()
return word_features
word_features = get_word_features(get_words_in_tweets(tweets))
print word_features
In [ ]:
# To create a classifier, we need to decide what features are relevant.
# To do that, we first need a feature extractor.
# The one we are going to use returns a dictionary indicating what words are contained in the input passed.
# Here, the input is the tweet. We use the word features list defined above along with the input
# to create the dictionary
def extract_features(document):
document_words = set(document)
features = {}
for word in word_features:
features['contains(%s)' % word] = (word in document_words)
return features
print(extract_features(['love', 'this', 'car']))
In [ ]:
# With our feature extractor, we can apply the features to our classifier using the method apply_features.
# We pass the feature extractor along with the tweets list defined above.
training_set = nltk.classify.apply_features(extract_features, tweets)
print training_set
In [ ]:
# Now that we have our training set, we can train our classifier.
classifier = nltk.NaiveBayesClassifier.train(training_set)
print classifier.show_most_informative_features(32)
In [ ]:
tweet = 'Larry is my friend'
print classifier.classify(extract_features(tweet.split()))
In [ ]:
In [3]:
%%writefile preprocesadorTweets.py
import unicodedata
import json
import re
import random
def leeArchivoTweets(archivo):
with open(archivo, 'r') as f:
tweets = json.load(f)
return tweets
emoticons_str = r"""
(?:
[:=;] # Eyes
[oO\-]? # Nose (optional)
[D\)\]\(\]/\\OpP] # Mouth
)"""
regex_str = [
emoticons_str,
r'<[^>]+>', # HTML tags
r'(?:@[\w_]+)', # @-mentions
r"(?:\#+[\w_]+[\w\'_\-]*[\w_]+)", # hash-tags
r'http[s]?://(?:[a-z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-f][0-9a-f]))+', # URLs
r'(?:(?:\d+,?)+(?:\.?\d+)?)', # numbers
r"(?:[a-z][a-z'\-_]+[a-z])", # words with - and '
r'(?:[\w_]+)', # other words
r'(?:\S)' # anything else
]
tokens_re = re.compile(r'('+'|'.join(regex_str)+')', re.VERBOSE | re.IGNORECASE | re.UNICODE)
emoticon_re = re.compile(r'^'+emoticons_str+'$', re.VERBOSE | re.IGNORECASE | re.UNICODE)
def eliminaTildes(s):
return ''.join((c for c in unicodedata.normalize('NFD', s) if unicodedata.category(c) != 'Mn'))
def strip_non_ascii(string):
''' Returns the string without non ASCII characters'''
stripped = (c.encode('ascii') for c in string if 0 < ord(c) < 127)
return ''.join(stripped)
def strip_less_than_3_chars(string):
''' Returns the string without non ASCII characters'''
stripped = (c for c in string if len(c)>3)
return ''.join(stripped)
def tokenize(s):
return tokens_re.findall(s)
def preprocesa(s):
try:
sinTildes = eliminaTildes(s)
ascii_string = strip_non_ascii(sinTildes)
tokens = tokenize(ascii_string)
tokens = [token.lower() for token in tokens if len(token) > 3 and not token.startswith('http')]
return tokens
except TypeError:
return None
def preprocesaTweets(tweets, periodico):
""" El sentimiento inicial de los tweets es aleatorio"""
return [(preprocesa(tweet[1]),random.choice(['positive', 'negative'])) for tweet in tweets[periodico]]
def preprocesaTweet(tweet, sentimiento):
""" Esta funcion espera un tweet en formato ascii"""
tokens = tokenize(tweet)
tokens = [token.lower() for token in tokens if len(token) > 3 and not token.startswith('http')]
return (tokens,sentimiento)
In [2]:
%%writefile clasificadorBayesiano.py
import preprocesadorTweets as preprocesador
import nltk
from nltk.corpus import stopwords
class Clasificador():
def __init__(self, train_tweets):
self.word_features = self.get_word_features(self.get_words_in_tweets(train_tweets))
# The list of word features need to be extracted from the tweets.
# It is a list with every distinct words ordered by frequency of appearance.
# We use the following function to get the list plus the two helper functions.
def get_words_in_tweets(self,tweets):
all_words = []
for (words, sentiment) in tweets:
all_words.extend(words)
return all_words
def get_word_features(self,wordlist):
wordlist = nltk.FreqDist(wordlist)
word_features = wordlist.keys()
return word_features
# To create a classifier, we need to decide what features are relevant.
# To do that, we first need a feature extractor.
# The one we are going to use returns a dictionary indicating what words are contained in the input passed.
# Here, the input is the tweet. We use the word features list defined above along with the input
# to create the dictionary
def extract_features(self,document):
document_words = set(document)
features = {}
for word in self.word_features:
features['contains(%s)' % word] = (word in document_words)
return features
def entrenaClasificador(self,train_tweets):
# With our feature extractor, we can apply the features to our classifier using the method apply_features.
# We pass the feature extractor along with the tweets list defined above.
training_set = nltk.classify.apply_features(self.extract_features, train_tweets)
# Now that we have our training set, we can train our classifier.
return nltk.NaiveBayesClassifier.train(training_set)
def clasifica(self,clasificador, tweet):
return clasificador.classify(self.extract_features(tweet.split()))
def cambiaSentimiento(self,tweets, tweetConNuevoSentimiento, sentimiento):
"""Cambiando un tweet de sentimiento
tweetConNuevoSentimiento = 'RT @elpais_opinion: No se equivoquen, la campa\xf1a electoral es una
extirpaci\xf3n de los recuerdos. David Trueba explica por qu\xe9 https://t.co/u\u2026' """
tweetConNuevoSentimiento = preprocesador.preprocesaTweet(tweetConNuevoSentimiento, sentimiento)
for index,tweet in enumerate(tweets):
if tweets[index][0] == tweetConNuevoSentimiento[0]:
del tweets[index]
tweets.append(tweetConNuevoSentimiento)
return tweets
In [ ]:
tweetConNuevoSentimiento = """RT @elpais_opinion: No se equivoquen, la campa\xf1a electoral es una
extirpaci\xf3n de los recuerdos. David Trueba explica por qu\xe9 https://t.co/u\u2026"""
nuevosTweets = cambiaSentimiento(tweets_elpais_procesados, tweetConNuevoSentimiento, 'negative')
print(nuevosTweets)
In [7]:
import clasificadorBayesiano
train_tweets=[(['love', 'this', 'car'], 'positive'), (['this', 'view', 'amazing'], 'positive'),
(['feel', 'great', 'this', 'morning'], 'positive'), (['excited', 'about', 'the', 'concert'], 'positive'),
(['best', 'friend'], 'positive'), (['not', 'like', 'this', 'car'], 'negative'),
(['this', 'view', 'horrible'], 'negative'), (['feel', 'tired', 'this', 'morning'], 'negative'),
(['not', 'looking', 'forward', 'the', 'concert'], 'negative'), (['enemy'], 'negative')]
test_tweets = [(['feel', 'happy', 'this', 'morning'], 'positive'),
(['larry', 'friend'], 'positive'),
(['not', 'like', 'that', 'man'], 'negative'),
(['house', 'not', 'great'], 'negative'),
(['your', 'song', 'annoying'], 'negative')]
# Los train_tweets iniciales son para coger las palabras sobre las que va calcular las probabilidades
cl = clasificadorBayesiano.Clasificador(train_tweets)
# Los train_tweets siguientes son para entrenar al clasificador
clasificador = cl.entrenaClasificador(train_tweets)
#print clasificador.show_most_informative_features(32)
tweet = 'Larry is my friend'
print cl.clasifica(clasificador, tweet)
#Llega mas informacion
train_tweets.extend(test_tweets)
clasificador = cl.entrenaClasificador(train_tweets)
#print clasificador.show_most_informative_features(32)
tweet = 'Larry is my friend'
print cl.clasifica(clasificador, tweet)
In [8]:
import preprocesadorTweets as preprocesador
import clasificadorBayesiano
#-----------------------------------------------------------------------------------------------------
# -------------------------- Preparando y entrenando inicialmente al clasificador --------------------
#-----------------------------------------------------------------------------------------------------
periodicos = ['elmundoes', 'el_pais', 'abc_es','larazon_es',
'eldiarioes','publico_es','20m']
periodicosEntrenamiento = ['elmundoes', 'el_pais', 'abc_es','eldiarioes','20m']
tweetsBase = preprocesador.leeArchivoTweets("periodicos_4horas.json")
tweetsEntrenamiento = preprocesador.leeArchivoTweets("periodicos.json")
tweetsBaseProcesados = []
for periodico in periodicos:
tweetsBaseProcesados.extend(preprocesador.preprocesaTweets(tweetsBase,periodico))
tweetsEntrenamientoProcesados = []
for periodico in periodicosEntrenamiento:
tweetsEntrenamientoProcesados.extend(preprocesador.preprocesaTweets(tweetsEntrenamiento,periodico))
#print(len(tweetsBaseProcesados))
#print(tweetsBaseProcesados)
#print(len(tweetsEntrenamientoProcesados))
#print(tweetsEntrenamientoProcesados)
# Los tweets iniciales son para coger las palabras sobre las que va calcular las probabilidades
cl = clasificadorBayesiano.Clasificador(tweetsBaseProcesados)
# Los tweetsEntrenamientoProcesados siguientes son para entrenar al clasificador
clasificador = cl.entrenaClasificador(tweetsEntrenamientoProcesados)
#print clasificador.show_most_informative_features(10)
#-----------------------------------------------------------------------------------------------------
# --------Al llegar nuevos tweets los clasifico y vuelvo a entrenar al clasificador con ellos --------
#-----------------------------------------------------------------------------------------------------
tweetsLlegados = []
nuevoTweet_texto = "Al menos siete muertos en un ataque de los talibanes a un aeropuerto de Afganistan"
nuevoTweet_sentimiento = cl.clasifica(clasificador, nuevoTweet_texto)
nuevoTweetProcesado = preprocesador.preprocesaTweet(nuevoTweet_texto, nuevoTweet_sentimiento)
print("clasificacion inicial: " + str(nuevoTweetProcesado))
#Vuelvo a entrenar al clasificador con el nuevo tweet que ha entrado junto con todos los anteriores
tweetsEntrenamientoProcesados.append(nuevoTweetProcesado)
clasificador = cl.entrenaClasificador(tweetsEntrenamientoProcesados)
#print clasificador.show_most_informative_features(10)
#-----------------------------------------------------------------------------------------------------
# -------------------------- Cambio un tweet de sentimiento --------------------
#-----------------------------------------------------------------------------------------------------
tweetsEntrenamientoProcesados = cl.cambiaSentimiento(tweetsEntrenamientoProcesados,
"Al menos siete muertos en un ataque de los talibanes a un aeropuerto de Afganistan",
'positive')
clasificador = cl.entrenaClasificador(tweetsEntrenamientoProcesados)
#print clasificador.show_most_informative_features(10)
print("")
print("Cambio de sentimiento respecto al tweet " + str(tweetsEntrenamientoProcesados[-1]))
print("")
print ("clasificacion tras cambio sentimiento: %s " % cl.clasifica(clasificador, nuevoTweet_texto))
In [43]:
%%writefile clasificadorPrensa.py
import preprocesadorTweets as preprocesador
import clasificadorBayesiano
class ClasificadorPrensa():
def __init__(self):
self.periodicos = ['elmundoes', 'el_pais', 'abc_es','larazon_es',
'eldiarioes','publico_es','20m']
self.periodicosEntrenamiento = ['elmundoes', 'el_pais', 'abc_es','eldiarioes','20m']
self.tweetsBaseProcesados = self.extraeTweets("periodicos_4horas.json", self.periodicos)
self.tweetsEntrenamientoProcesados = self.extraeTweets("periodicos.json", self.periodicosEntrenamiento)
self.clasificador = clasificadorBayesiano.Clasificador(self.tweetsBaseProcesados)
self.clasificadorEntrenado = self.clasificador.entrenaClasificador(self.tweetsEntrenamientoProcesados)
def extraeTweets(self, archivo, periodicos):
tweets = preprocesador.leeArchivoTweets(archivo)
tweetsProcesados = []
for periodico in periodicos:
tweetsProcesados.extend(preprocesador.preprocesaTweets(tweets,periodico))
return tweetsProcesados
def clasificaNuevoTweet(self, nuevoTweet_texto):
""" Da la clasificacion del Tweet segun el clasificador bayesiano ('positive' o 'negative')
y vuelve a entrenar al clasificador con esta informacion"""
nuevoTweet_sentimiento = self.clasificador.clasifica(self.clasificadorEntrenado, nuevoTweet_texto)
nuevoTweetProcesado = preprocesador.preprocesaTweet(nuevoTweet_texto, nuevoTweet_sentimiento)
#Vuelvo a entrenar al clasificador con el nuevo tweet que ha entrado junto con todos los anteriores
self.tweetsEntrenamientoProcesados.append(nuevoTweetProcesado)
self.clasificadorEntrenado = self.clasificador.entrenaClasificador(self.tweetsEntrenamientoProcesados)
return nuevoTweet_sentimiento
def cambiaSentimiento(self, tweet_texto,nuevoSentimiento):
self.tweetsEntrenamientoProcesados = self.clasificador.cambiaSentimiento(self.tweetsEntrenamientoProcesados,
tweet_texto, nuevoSentimiento)
self.clasificadorEntrenado = self.clasificador.entrenaClasificador(self.tweetsEntrenamientoProcesados)
In [38]:
c = ClasificadorPrensa()
#print(c.tweetsEntrenamientoProcesados)
#c.clasificadorEntrenado.show_most_informative_features(10)
print c.clasificaNuevoTweet("Al menos siete muertos en un ataque de los talibanes a un aeropuerto de Afganistan")
#c.clasificadorEntrenado.show_most_informative_features(10)
c.cambiaSentimiento("Al menos siete muertos en un ataque de los talibanes a un aeropuerto de Afganistan",'positive')
print("Tras el cambio de sentimiento " + str(c.tweetsEntrenamientoProcesados[-1]))
In [ ]: